/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.gmail.higginson555.adam.gui;

import com.gmail.higginson555.adam.AccountMessageDownloader;
import com.gmail.higginson555.adam.ClientThreadPool;
import com.gmail.higginson555.adam.FindMessageQueueItem;
import com.gmail.higginson555.adam.UserDatabase;
import com.gmail.higginson555.adam.queryParser.QueryParseException;
import com.gmail.higginson555.adam.view.EmailFilterer;
import com.gmail.higginson555.adam.view.View;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import javax.mail.Message;
import javax.swing.JOptionPane;

/**
 *
 * @author Adam
 */
public class ViewPanel extends javax.swing.JPanel implements PropertyListener
{

    //The view this panel represents
    private View view;
    //All the data this view holds after being filtered, messageID mapped to data
    private ArrayList<Object[]> filterData;
    //Messages being searched
    private HashMap<String, Object[]> currentSearchList;
    //Listeners
    private ArrayList<PropertyListener> listeners;
    
    private EmailTableCellRenderer cellRenderer;
    
    /**
     * Creates new form ViewPanel
     */
    public ViewPanel(View view) {
        if (view == null)
            System.out.println("View null!");
        this.view = view;
        this.currentSearchList = new HashMap<String, Object[]>();
        this.setName(view.getViewName());
        initComponents();
        this.queryField.setText(this.view.getQuery());
        this.cellRenderer = new EmailTableCellRenderer();
        this.messageTable.setAutoCreateRowSorter(true);
        updateTableWithNewData();
        this.messageTable.setDefaultRenderer(Object.class, cellRenderer);
        this.listeners = new ArrayList<PropertyListener>();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        viewNameLabel = new javax.swing.JLabel();
        messagesLabel = new javax.swing.JLabel();
        jSeparator1 = new javax.swing.JSeparator();
        jScrollPane1 = new javax.swing.JScrollPane();
        messageTable = new javax.swing.JTable();
        refreshButton = new javax.swing.JButton();
        queryLabel = new javax.swing.JLabel();
        queryField = new javax.swing.JTextField();
        editButton = new javax.swing.JButton();

        viewNameLabel.setFont(new java.awt.Font("Tahoma", 1, 18)); // NOI18N
        viewNameLabel.setText(view.getViewName());

        messagesLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        messagesLabel.setText("Messages");

        messageTable.setModel(new EmailTableModel());
        messageTable.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                messageTableMouseClicked(evt);
            }
        });
        jScrollPane1.setViewportView(messageTable);

        refreshButton.setText("Refresh");
        refreshButton.setToolTipText("While updating e-mail data, you may need to refresh as data is downloaded");
        refreshButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                refreshButtonActionPerformed(evt);
            }
        });

        queryLabel.setFont(new java.awt.Font("DejaVu Sans", 1, 13)); // NOI18N
        queryLabel.setText("Query:");

        editButton.setText("Edit");
        editButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                editButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jSeparator1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 741, Short.MAX_VALUE)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 717, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
                        .addComponent(queryLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(queryField, javax.swing.GroupLayout.DEFAULT_SIZE, 582, Short.MAX_VALUE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(refreshButton))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(messagesLabel)
                        .addGap(0, 0, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(viewNameLabel)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(editButton, javax.swing.GroupLayout.PREFERRED_SIZE, 121, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(viewNameLabel)
                    .addComponent(editButton))
                .addGap(4, 4, 4)
                .addComponent(jSeparator1, javax.swing.GroupLayout.PREFERRED_SIZE, 10, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(18, 18, 18)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(queryField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(queryLabel)
                    .addComponent(refreshButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(messagesLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 453, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>//GEN-END:initComponents

    private void publishPropertyEvent(String name, Object Value)
    {
        for (PropertyListener listener : listeners)
        {
            listener.onPropertyEvent(this.getClass(), name, Value);
        }
    }

    public void addListener(PropertyListener listener)
    {
        listeners.add(listener);
    }

    private void updateTableWithNewData()
    {
        if (!queryField.getText().isEmpty())
        {
            try
            {
                view.setQuery(queryField.getText());
            }
            catch (SQLException ex)
            {
                JOptionPane.showMessageDialog(null, "Lost connection to the SQL Server!", "SQLException", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
        }
        if (view.getQuery() != null && !view.getQuery().isEmpty())
        {
            try 
            {
                Object[][] tableData = view.getQueryResults();
                Object[][] newTableData = new Object[tableData.length][4];
                filterData = new ArrayList<Object[]>(tableData.length);
                EmailTableModel model = (EmailTableModel) messageTable.getModel();
                int row = 0;
                for (Object[] line : tableData)
                {
                    //System.out.println("Adding: " + Arrays.toString(line) + " at index: " + row);
                    filterData.add(row, line);
                    Object[] tableLine = {line[2], line[3], line[6], line[12]};
                    //System.out.println("Table line: " + Arrays.toString(tableLine));
                    newTableData[row] = tableLine;
                    row++;
                }

                if (newTableData.length != 0)
                {
                    System.out.println("Setting new table data with size: " + newTableData.length);
                    cellRenderer.setTableData(filterData);
                    model.setData(newTableData);
                }

                //messageTable.setModel(model);
                
            } catch (QueryParseException ex) {
                JOptionPane.showMessageDialog(this, ex.getMessage(), "QueryException!", JOptionPane.ERROR_MESSAGE);
            } catch (SQLException ex) {
                JOptionPane.showMessageDialog(this, ex.getMessage(), "SQLException!", JOptionPane.ERROR_MESSAGE);
                ex.printStackTrace();
            }
            
        }
        else
        {
            EmailFilterer filterer = EmailFilterer.getInstance(view.getAccount());
            try
            {
                filterData = filterer.getTableData(view);
                Object[][] newTableData = new Object[filterData.size()][4]; 
                EmailTableModel model = (EmailTableModel) messageTable.getModel();
                int row = 0;
                for (Object[] line : filterData)
                {
                    Object[] tableLine = {line[2], line[3], line[6], Boolean.TRUE};
                    newTableData[row] = tableLine;
                    row++;
                }

                model.setData(newTableData);
            } 
            catch (SQLException ex)
            {
                JOptionPane.showMessageDialog(this, ex.getMessage(), "SQLException", JOptionPane.ERROR_MESSAGE);
            }
        }
    }
    
    private void messageTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_messageTableMouseClicked
        //Double click
        if (evt.getClickCount() == 2)
        {
            //Get selected row
            int index = messageTable.convertRowIndexToModel(messageTable.getSelectedRow());
            System.out.println("Selected: " + index);
            //Get the data from this selected row
            Object[] line = filterData.get(index);
            //Get the message UID and folder ID
            int folderID = (Integer) line[7];
            String messageUID = (String) line[1];
            int messageID = (Integer) line[0];
            long seqNo = (Long) line[10];
            boolean shouldExtractTags = !(Boolean) line[9];
            try 
            {
                //Find message with this data
                Message foundMessage = AccountMessageDownloader.getInstance(view.getAccount()).getMessageWithID(folderID, seqNo);
                if (foundMessage == null)
                {
                    int result = JOptionPane.showConfirmDialog(this, "Can't find message, click ok to begin searching", "Information", JOptionPane.OK_CANCEL_OPTION);
                    if (result == JOptionPane.OK_OPTION)
                    {
                        ClientThreadPool.findMessageQueue.add(new FindMessageQueueItem(this, line));
                        line[11] = false;
                        cellRenderer.updateTableDataEntry(index, line);
                        currentSearchList.put(messageUID, line);
                    }
                    
                    return;
                }
                else
                {
                    System.out.println("Found message titled: " + foundMessage.getSubject());
                    //ViewMailScreen vms = new ViewMailScreen(foundMessage, view.getAccount(), messageID, shouldExtractTags);
                    //vms.setVisible(true);
                    Object[] data = {foundMessage, view.getAccount(), messageID, shouldExtractTags};
                    line[12] = true;
                    UserDatabase.getInstance().updateRecord("Messages", "isRead=1", "messageUID='" + messageUID + "'");
                    publishPropertyEvent("MessageOpened", data);
                }
            } 
            catch (Exception ex)
            {
                ex.printStackTrace();
                JOptionPane.showMessageDialog(this, ex.toString(), ex.getClass().getName(), JOptionPane.ERROR_MESSAGE);
            }
        }
    }//GEN-LAST:event_messageTableMouseClicked

    private void refreshButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_refreshButtonActionPerformed
        updateTableWithNewData();
    }//GEN-LAST:event_refreshButtonActionPerformed

    private void editButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editButtonActionPerformed
        
        String input = JOptionPane.showInputDialog(null, "Please Enter a new title: ", "View Name", JOptionPane.OK_CANCEL_OPTION);
        if (input != null)
        {
            if (input.equalsIgnoreCase(view.getViewName()))
            {
                return;
            }
            else if (input.isEmpty())
            {
                JOptionPane.showMessageDialog(null, "Must enter a view name!", "Error", JOptionPane.ERROR_MESSAGE);
            }
            else
            {
                try
                {
                    String oldName = view.getViewName();
                    if (!view.setName(input))
                    {
                        JOptionPane.showMessageDialog(null, "View name not unique!", "Error", JOptionPane.ERROR_MESSAGE);
                    }
                    else
                    {
                        viewNameLabel.setText(input);
                        this.setName(input);
                        Object[] data = {view.getAccount(), oldName};
                        publishPropertyEvent("ViewNameChanged", data);
                    }
                } 
                catch (SQLException ex)
                {
                    JOptionPane.showMessageDialog(this, ex.toString(), ex.getClass().getName(), JOptionPane.ERROR_MESSAGE);
                    ex.printStackTrace();
                }
            }
        }
    }//GEN-LAST:event_editButtonActionPerformed

    @Override
    public void onPropertyEvent(Class source, String name, Object value) 
    {
        if (name.equalsIgnoreCase("foundMessage"))
        {
            System.out.println("Returned to GUI thread");
            Object[] newMessageData = (Object[]) value;
            System.out.println("New message data: " + newMessageData);
            Object[] oldData = currentSearchList.remove((String) newMessageData[1]);
            int index = filterData.indexOf(oldData);
            System.out.println("Removed old data: " + filterData.remove(oldData));
            filterData.add(index, newMessageData);
            JOptionPane.showMessageDialog(null, "Found message titled: " + (String) newMessageData[2], 
                    "Found Message", JOptionPane.INFORMATION_MESSAGE);
        }
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton editButton;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JSeparator jSeparator1;
    private javax.swing.JTable messageTable;
    private javax.swing.JLabel messagesLabel;
    private javax.swing.JTextField queryField;
    private javax.swing.JLabel queryLabel;
    private javax.swing.JButton refreshButton;
    private javax.swing.JLabel viewNameLabel;
    // End of variables declaration//GEN-END:variables


}
